package entity.building;

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics2D;
import java.util.LinkedList;

import user.Button;

import levels.PathFinder;
import levels.PathGrid;
import loading.ImageLoader;
import main.GameList;
import math.Vector2D;
import entity.Attackable;
import entity.Entity;
import entity.units.GroundUnit;
import entity.units.Unit;

public abstract class Building extends Entity implements Attackable
{
	private PathGrid pg;
	
	private int health, totalHealth;
	private double timeBuilding;
	private double timeToBuild;
	
	private LinkedList<Unit> unitQueue;
	
	private Vector2D rallyPoint;
	
	private LinkedList<Button> options;

	public Building( Vector2D pos, ImageLoader img, PathGrid pg, double timeToBuild, int totalHealth )
	{
		super( pos, img );
		
		this.pg = pg;
		
		this.totalHealth = health = totalHealth;
		
		this.timeToBuild = timeToBuild;
		this.timeBuilding = 0;
		
		options = new LinkedList<Button>();
		
		unitQueue = new LinkedList<Unit>();
		
		rallyPoint = this.getTopLeftCorner();
		
		int left = img.width() / 32;
		int down = img.height() / 32;
		
		Vector2D posGrid = PathGrid.fromWorldToGrid( this.getTopLeftCorner() );
		
		for( int y = (int)posGrid.getY(); y < (int)posGrid.getY() + down; y++ )
		{
			for( int x = (int)posGrid.getX(); x < (int)posGrid.getX() + left; x++ )
			{
				pg.getTiles().get( y ).get( x ).setOccupied( true ); 
			}
		}
	}
	
	public abstract boolean testOptions( Vector2D mouse, GameList list, PathFinder pf );
	
	public LinkedList<Button> getOptions()
	{
		return options;
	}
	
	protected void addOption( Button b )
	{
		options.add( b );
	}
	
	public void setRallyPoint( Vector2D v )
	{
		rallyPoint = v;
	}
	
	public void train( Unit u )
	{	
		unitQueue.add( u );
		
	}
	
	protected LinkedList<Unit> getQueue()
	{
		return unitQueue;
	}
	
	public void update( double duration )
	{
		super.update( duration );
		
		if( !unitQueue.isEmpty() )
		{
			if( unitQueue.get( 0 ).isTrained() )
			{
				unitQueue.get( 0 ).goTo( rallyPoint );
				unitQueue.remove( 0 );
			}
			else
			{
				unitQueue.get( 0 ).incTimeTraining( duration );
			}
		}
	}
	
	public void draw( Graphics2D g )
	{
		if( isBuilt() )
		{
			super.draw( g );
		}
		else
		{
			g.setComposite( AlphaComposite.getInstance( AlphaComposite.SRC_OVER, 0.4f ) );

			super.draw( g );
            
    		g.setComposite( AlphaComposite.getInstance( AlphaComposite.SRC_OVER, 1.0f ) );
		}
	}
	
	/**
	 * After the building is dead it no longer blocks any nodes, so it should be reset to not occupied.
	 */
	public void resetNodes()
	{
		int left = this.getImage().width() / 32;
		int down = this.getImage().height() / 32;
		
		Vector2D posGrid = PathGrid.fromWorldToGrid( this.getTopLeftCorner() );
		
		for( int y = (int)posGrid.getY(); y < (int)posGrid.getY() + down; y++ )
		{
			for( int x = (int)posGrid.getX(); x < (int)posGrid.getX() + left; x++ )
			{
				pg.getTiles().get( y ).get( x ).setOccupied( false ); 
			}
		}
	}
	
	public Vector2D getClosestAttackLocation( Vector2D pos )
	{
		Vector2D min = Vector2D.add( getPosition(), new Vector2D( -getImage().width() / 2.0 - 1, -getImage().height() / 2.0 - 1 ) );
		double minDistance = min.distance( pos );
		
		Vector2D v = Vector2D.add( getPosition(), new Vector2D( 0, -getImage().height() / 2.0 - 1 ) );
		double d = v.distance( pos );
		
		v = Vector2D.add( getPosition(), new Vector2D( getImage().width() / 2.0 + 1, -getImage().height() / 2.0 - 1 ) );
		d = v.distance( pos );
		
		if( d < minDistance )
		{
			minDistance = d;
			min = v;
		}

		v = Vector2D.add( getPosition(), new Vector2D( getImage().width() / 2.0 + 1, 0 ) );
		d = v.distance( pos );

		if( d < minDistance )
		{
			minDistance = d;
			min = v;
		}
		
		v = Vector2D.add( getPosition(), new Vector2D( getImage().width() / 2.0 + 1, getImage().height() / 2.0 + 1 ) );
		d = v.distance( pos );
		
		if( d < minDistance )
		{
			minDistance = d;
			min = v;
		}

		v = Vector2D.add( getPosition(), new Vector2D( 0, getImage().height() / 2.0 + 1 ) );
		d = v.distance( pos );
		
		if( d < minDistance )
		{
			minDistance = d;
			min = v;
		}

		v = Vector2D.add( getPosition(), new Vector2D( -getImage().width() / 2.0 - 1, getImage().height() / 2.0 + 1 ) );
		d = v.distance( pos );
		
		if( d < minDistance )
		{
			minDistance = d;
			min = v;
		}

		v = Vector2D.add( getPosition(), new Vector2D( -getImage().width() / 2.0 - 1, 0 ) );
		d = v.distance( pos );
		
		if( d < minDistance )
		{
			minDistance = d;
			min = v;
		}
		
		return min;
	}
	
	public double getTimetoBuild()
	{
		return timeToBuild;
	}
	
	public double getTimeBuilding()
	{
		return timeBuilding;
	}
	
	public void incTimeBuilding( double d )
	{
		timeBuilding += d;
	}
	
	public boolean isBuilt()
	{
		return timeBuilding >= timeToBuild;
	}
	
	/**
	 *	Builders use this position as the location they move to to build the building.
	 */
	public Vector2D getTopLeftCorner()
	{
		return Vector2D.subtract( getPosition(), new Vector2D( getImage().width() / 2.0, getImage().height() / 2.0 ) );
	}
	
	public boolean isDead()
	{
		return health <= 0;
	}

	public void damage( int amount )
	{
		health -= amount;
	}
}
